using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Engine.Media;
using SCPAK2;
namespace SCPAK
{
    public class UnPak
    {
        public int Version = 0;
        public int selectVersion = 0;
        public static byte[] contentPad = new byte[1]{ 63};
        public static byte[] Pad22()
        {
            return Encoding.UTF8.GetBytes("tiTrKAXRpwuRhNI3gTkxIun6AyLxSZaIgEjVkyFWhD6w0QgwmN5YwykY2I79OHIolI1r4ewZ2uEfStqC7GRDM8CRTNQTdg91pkOkbnIPAiEp2EqkZWYPgPv6CNZpB3E1OuuBmR3ZzYEv8UMjQxjyXZy1CEOD8guk3uiiPvyFaf5pSznSNWXbnhmAzTbi1TEGCyhxejMTB23KUgqNiskGlrHaIVNz83DXVGkvm");
        }
        public static byte[] Pad23()
        {
            string text = string.Empty;
            string text2 = "0123456789abdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            Engine.Random random = new Engine.Random(9213);
            for (int i = 0; i < 229; i++)
            {
                text += text2[random.Int(text2.Length)];
            }
            return Encoding.UTF8.GetBytes(text);
        }

        public UnPak(string pakFile,int v, MainActivity activity)
        {
            selectVersion = v;
            if (!File.Exists(pakFile))
            {
                throw new FileNotFoundException("文件不存在！");
            }
            string pakDirectory = Path.GetDirectoryName(pakFile) + "/" + Path.GetFileNameWithoutExtension(pakFile);
            var list = ReadPakList(pakFile, v == 2 ? Pad22() : Pad23(), (n) => { return true; });
            Load(list, Version - 20, pakDirectory, activity);
        }
        public static List<PakInfo> ReadPakList(string fullpath, out int Version)
        {
            List<PakInfo> pakinfos = null;
            try
            {
                pakinfos = ReadPakList(fullpath, Pad23());
                Version = 23;
            }
            catch
            {
                try
                {
                    pakinfos = ReadPakList(fullpath, Pad22());
                    Version = 22;
                }
                catch
                {
                    Version = 0;
                    throw new FileNotFoundException("不能识别的Pak2包");
                }
            }
            return pakinfos;
        }

        public static List<PakInfo> ReadPakList(string fullpath, byte[] pads, Func<string, bool> Condition = null)
        {
            List<PakInfo> list = new List<PakInfo>();
            using (FileStream fileStream = new FileStream(fullpath, FileMode.Open))
            {
                PadStream padStream = new PadStream(fileStream, pads);
                BinaryReader binaryReader = new BinaryReader(padStream, Encoding.UTF8, leaveOpen: true);
                byte[] array = new byte[4];
                if (fileStream.Read(array, 0, array.Length) != array.Length || array[0] != 80 || array[1] != 75 || array[2] != 50 || array[3] != 0)
                {
                    throw new FileLoadException("该文件不是Survivalcraft2(2.2/2.3)的PAK文件！");
                }
                long num = binaryReader.ReadInt64();
                int num2 = binaryReader.ReadInt32();
                for (int i = 0; i < num2; i++)
                {
                    string fileName = binaryReader.ReadString();
                    string typeName = binaryReader.ReadString();
                    long position = binaryReader.ReadInt64() + num;
                    long bytesCount = binaryReader.ReadInt64();
                    long position2 = binaryReader.BaseStream.Position;
                    PakInfo pakInfo = new PakInfo()
                    {
                        fileName = fileName,
                        typeName = typeName
                    };
                    if (Condition != null && Condition(fileName))
                    {
                        pakInfo.fileStream = ContentFile(padStream, pads, position, bytesCount);
                        list.Add(pakInfo);
                    }else if (Condition == null) list.Add(pakInfo);
                    binaryReader.BaseStream.Position = position2;
                }
            }
            return list;
        }

        public static Stream ContentFile(PadStream padStream,byte[] pads, long position, long bytesCount)
        {
            padStream.keys = contentPad;
            padStream.Position = position;
            byte[] array = new byte[bytesCount];
            for (long num = 0L; num < bytesCount; num++)
            {
                array[num] = (byte)padStream.ReadByte();
            }
            MemoryStream result = new MemoryStream(array, writable: false);
            padStream.keys = pads;
            return result;
        }

        public static string GetExtension(string typename) {

            switch (typename)
            {
                case "System.String":return ".txt";
                case "System.Xml.Linq.XElement": return ".xml";
                case "Engine.Media.StreamingSource": return ".ogg";
                case "Engine.Graphics.Texture2D": return ".png";
                case "Engine.Audio.SoundBuffer": return ".wav";
                case "Engine.Graphics.Model": return ".dae";
                case "Engine.Graphics.Shader": return ".shader";
                case "Engine.Media.BitmapFont": return ".font";
            }
            return string.Empty;
        }
        public static void Load(List<PakInfo> listFileStream, int version, string pakDirectory, MainActivity mainActivity)
        {
            foreach (PakInfo item in listFileStream)
            {
                Stream stream = null;
                try
                {
                    if (item.fileStream == null) throw new Exception("解压的源文件流不能为空");
                    if (version == 2) mainActivity.sendDialog("[2.2]解包中...", "解包文件 " + item.fileName);
                    else if (version == 3) mainActivity.sendDialog("[2.3]解包中...", "解包文件 " + item.fileName);
                    switch (item.typeName)
                    {
                        case "System.String":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".txt");
                            TextHandler.RecoverText(stream, item.fileStream);
                            break;
                        case "System.Xml.Linq.XElement":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".xml");
                            TextHandler.RecoverText(stream, item.fileStream);
                            break;
                        case "Engine.Media.StreamingSource":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".ogg");
                            item.fileStream.CopyTo(stream);
                            break;
                        case "Engine.Graphics.Texture2D":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".png");
                            Texture2DHandler.RecoverTexture2D(stream, item.fileStream);
                            break;
                        case "Engine.Audio.SoundBuffer":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".wav");
                            if (version == 2) SoundHandler.Save22(stream, item.fileStream);
                            else
                            {
                                SoundHandler.Save23(stream, item.fileStream);
                            }
                            break;
                        case "Engine.Graphics.Model":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".dae");
                            ModelHandler.RecoverModel(stream, item.fileStream);
                            break;
                        case "Engine.Graphics.Shader":
                            stream = CreateFile(pakDirectory + "/" + item.fileName + ".shader");
                            item.fileStream.CopyTo(stream);
                            break;
                        case "Engine.Media.BitmapFont":
                            try
                            {
                                stream = CreateFile(pakDirectory + "/" + item.fileName + ".lst");
                                Stream stream2 = CreateFile(pakDirectory + "/" + item.fileName + ".png");
                                if (version == 2) {
                                    FontHandler.RecoverFont(stream, stream2, item.fileStream);
                                }
                                else FontHandler.Save23(stream, stream2, item.fileStream);

                                stream2.Dispose();
                            }
                            catch
                            {
                                item.fileStream.Position = 0L;
                                stream = CreateFile(pakDirectory + "/" + item.fileName + ".font");
                                item.fileStream.CopyTo(stream);
                            }
                            break;
                        default:
                            throw new Exception("发现无法识别的文件类型:" + item.typeName + "\t文件名称:" + item.fileName);
                    }
                }
                catch (Exception e)
                {
                    if (version == 2) mainActivity.sendDialog("[2.2]解包出错", "解包文件 " + item.fileName + "\n" + e.Message);
                    else mainActivity.sendDialog("[2.3]解包出错", "解包文件 " + item.fileName + "\n" + e.Message);
                }
                stream?.Dispose();
                item.fileStream.Dispose();
            }
        }

        public static FileStream CreateFile(string file)
        {
            string path = Path.GetDirectoryName(file);
            if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
            return new FileStream(file, FileMode.Create);

        }
    }
}
